This file is basically just a guide on how to get started with creating Triggers for TriGen.
LAST EDIT: 04/11/2017.

First, let me state the philosophies which were kept in mind while TriGen was being built (Feel free to skip this whole chunk if you don't care):

        1.
        One goal is to allow you to create large groups of triggers by typing as little as possible.

        This is made apparent in how a lot of the conditions and actions will 'assume' the rest
        of the inputs if you leave them blank.  For example, typing in 'command(cp, "Terran Marine")'
        actually accomplishes the same thing as if you were to type 'command("Current Player", "Terran Marine", "At least", 1)'.

        In general, good rules of thumb on how TriGen 'guesses' the rest of the trigger are the following:
        1. TriGen will have the triggers apply to "Current Player" when possible.
        2. TriGen will have conditions be the 'easiest' to be met (e.g. it uses 'at leasts' in death counters, command, etc. and it uses "Anywhere" in location conditions).
        3. TriGen will have actions be applied to as many things as possible (e.g. "All units" when applicable).

        Of course, These are just rules of thumb and not exact (there may be exceptions, or I may have just forgot to try to do them all the same way lol).
        As such, it is recommended to have the "Conditions" and "Actions" files open to double check the triggers if you are ever unsure.

        2.
        Syntax is very readable.

        For example, in actions in order to add one to a deathcounter or to resources, you type in the object and then + 1.
        e.g. lets say you want to add 1 to current players gas.  In the actions, what you write is simply: gas + 1
        You can also add two deathcounters with
        DC1 + DC2 
        to add the value of DC2 to DC1.

        3.
        Allows for complex conditions to be entered in very easily.
        
        For example, many people would like to compare two deathcounters values.
        To do this in game, you need something like 32 triggers.
        In TriGen however, all you need is 
        DC1 == DC2 
        in the conditions, and TriGen will take care of the rest for you.
        
        4.
        Allow for conditions and actions to be called in a number of ways.
        
        For example, let's say you want to detect "When Player 5 has accumulated at least 6 gas."  There are a number of ways to call this condition:
            i. if you have a player class defined for player 5, e.g. 
            
                P5 = Player(5)
                
                then in your conditions you may write 
                
                P5.accumulate("At least", 6, "gas")
                
            ii. if you don't want to define a P5 object, you can explicitely type:
                
                accumulate("Player 5", "At least", 6, "gas")
                
            iii. if you will be referencing Player 5's gas a lot, you might want the following object:
                p5gas = Resource("gas", "Player 5")
                
                and then in the conditions you type:
                
                p5gas >= 6

        
OKAY, lets just jump into it:

----------------------------------
--------------------------------------------
-----------------------------------
----------------------------------------
-------How to Create Triggers using TriGen--------
-----------------------------------
----------------------------------------
--------------------------------------
--------------------

First, an example:
Lets say you want the following trigger:

    Trigger("Player 1"){
    Conditions:
        Command("Current Player", "Terran Marine", "At least", 1);
    Actions:
        Display Text(always, "You only have 1 marine!!");
        Preserve Trigger();
    }


The syntax for doing this in TriGen is a lot easier:

    T( P=[1], C=[command(cp, "Terran Marine")], A=[display_text("You only have 1 marine!!")] )

And that's it. 

(
note that the "Preserve Trigger" is added automatically.  To not have this, add 'just_once = True' in the trigger.
for example:
    T( P=[1], C=[command(cp, "Terran Marine")], A=[display_text("You only have 1 marine!!")], just_once = True )
    
    would suppress the Preserve Trigger().
)

So, what is going on?
To make triggers, you enter in T().

Inside of the parenthesis, you enter 3 things:  The Players which own the Trigger, the Conditions, and the Actions.

I will break each of these up into their own sections.


----------------------------------
----------PLAYERS-----------
----------------------------------

For the Players, you enter P=[1], or P=[1,2,3] for multiple players.

Additionally for Players you can enter in text: P=["Player 1"], or P=["Force 2"].

Further, TriGen comes with a Player Class, which allows for players to call some conditions and actions.  Here is how you declare them:

P1 = Player("Player 1")

and then in triggers you can just type:

T( P=[P1], ... ).

For a list of what conditions you may call with players, see the "class_players.py" file in the TriGen folder.











----------------------------------
------------CONDITIONS------------
----------------------------------

For Conditions, you enter C=[condition1, condition2, ...].

Note that if you do not define C in the trigger, then the condition 'Always' will be automatically inserted.

    =======================
    =====AND, NOTS, ORS====
    =======================
    
    Now, a really cool feature of TriGen is that you can do 'or' statements 'and' statements, 'not' statments, and 'else' statments in conditions.  Here is how:

    Lets say you want something which is the equivalent of (( A and B ) or ( C and D )) in your conditions.  to accomplish this, do the following:

    T( ..., C=[ [A, B], 'o', [C, D] ], ... )

    Basically, the commas act as 'ands', the ''o'' character is an 'or' signal, and the brackets act as parenthesis.

    Similary, the way you do nots is with the 'n' character. e.g.
     
    T( ..., C=[ 'n', A ], ... )
    
    ==============
    =====ELSES====
    ==============
    
    to use elses, you add E=[---] into the Triger, where the --- are the actions to execute if conditions are not met.
    
    For example, lets say you want the equivalent of the following:
    
        if(A):
            blah blah
        else:
            this executes when A is not met
            
    
    In TriGen, you enter:
    
    T( P=[---], C=[A], A=[blah blah], E=[this executes when A is not met] ).
    
    you may also place triggers inside of E if you want if-else type statements.  For example
    
    T(  
        P=[---], 
        C=[A], 
        A=[blah blah], 
        E=[ T( 
                C=[B], 
                A=[blahblah2] ) ] 
    )
    
    Note that for this embedded trigger, as for all embedded triggers (triggers inside triggers basically), you do NOT enter in P=whatever.
    These triggers will always inherit the player of the Trigger in which they are embedded.
    
    ============================
    ====CUSTOM CONDITIONS=======
    ============================
    
    Have you ever wanted to detect burrowed units with a single condition?  Now you can!
    
    The best way to explain custom conditions is through an example, so I will use burrowed detection.
    
    First off, normally to detect if a unit is burrowed, you do the following steps:
        1. Move a very small location on your unit.
        2. Move another computer controlled unit to that location.
        3. If the moved unit is on the very small location, then your unit is burrowed.  If the moved unit is not, then your unit is not burrowed.
        4. Move the computer controlled unit back to some off-screen location.
        
    Now, implementing this in SCMDraft is a pain.  With TriGen, here is how you set this up:
    (Note I am using Player 8 as the computer player and a Firebat as his unit)
    
    First off, define the following for ease of writing later on:
    
    
    
    loc_small = Location("Location 0")
    firebat = Unit("Firebat")
    loc_firebat_location = Location("Location 1")
    
    loc_we_wanna_burrow_here = Location("Location 2")
    
    
    
    We will now create the custom condition 'burrowed.'  To do this, create the following function:
    
    
    
    def burrowed(location, unit = "Any unit", player = "Current Player", qmod = "At least", num = 1):
        out =   [   T( A=[  loc_small.move(player, unit, location), firebat.move("Anywhere", loc_small, "Player 8")] ) ]
        out.append( T( C=[ loc_small.bring("Player 8"), bring(player, unit, location, qmod, num) ], A=[True] ) )
        out.append( T( A=[firebat.move("Anywhere", loc_firebat_location, "Player 8")] ) )
        return out
    

    
    And now we can use the following condition in our triggers from now on:

    
    
    
    T( P=[1], C=[burrowed(loc_we_wanna_burrow_here)], A=[display_text("You have a unit burrowed at that 'we_wanna_burrow_here' location!")] )
    
    
    
    Question: What is the important thing to realize about what we just did?  
    
    Answer: The "True" boolian inside the function we just declared.
    
    With triggers which are imbedded in Conditions, you can add True into their actions, and then if this 'action' is ran, that entire trigger will be flagged as having been met.
    
    Kind of confusing, but lets look back at the example:  The overall trigger is "burrowed."  We want this whole function to be flagged as True when your unit is burrowed.
    At the point where the True boolian is inside of the embedded trigger, IF Player 8 brings the firebat to loc_small, that implies your unit is burrowed.
    Thus, we have the condition "loc_small.bring("Player 8")", and if this is met, then we want the OVERALL burrowed detection to register as True, so in the action we write True.
    
    
    
    
    
    
    
    
    
    
----------------------------------
---------ACTIONS-----------
----------------------------------

In the trigger you write T( ..., A=[action1, action2, ...] ).

You can also add (though it doesn't do anything) lists inside of here, e.g.
T( ..., A=[action1, [action2, action3], action4, ...] ).

As mentioned before, TriGen will automatically add Preserve Trigger to every trigger.

To make TriGen NOT do this, add a just_once = True modifier to the trigger.  e.g.:

T( ..., A=[action to be run just once], just_once = True )


    ============================
    ======EMBEDDED TRIGGERS=====
    ============================
    
    I heard you like triggers, so I put triggers in your triggers.
    
    Basically, lets say you want to only run some part of a trigger's actions if some other condition is met.
    
    The you do something like the following:
    
    T( ..., A=[action1, T( C=[extra conditions for these actions], A=[more actions] ), action2, action3, ... ] )
    
    This allows you to create custom 'macro actions.'
    
    e.g., for those who know how, you can add two deathcounters together using something like 32 triggers. (In TriGen, these are pre-built in in the DC class.)
    With TriGen, you can group whatever sequence of actions you want into a list and put this in an action later, or construct a function
    which outputs a list of actions and then put this into an action later.
    
    for example:
    
    list_of_actions = [action1, action2, action3]
    
    T( P=[---], C=[---], A=[some other actions, list_of_actions] )





    
    
    
    
    
    
    
    
----------------------------------
---------DISCRETIZERS-----------
----------------------------------
    

Sometimes in maps, you would like to have triggers that run once whenever the conditions have just been met.
i.e., you want the trigger to run when the conditions are met, but to run again the conditions at some point must be un-met first.

To do this in TriGen, you do the following:

disc_my_discretizer = Discretizer()

T( P=[player], C=[conditions], A=[actions], D=[disc_my_discretizer] )




For example, lets say you want the text message "You are out of ammo!" when a player has 0 gas, but of course you don't want this spammed at them while their gas is 0.

Here is how you would accomplish this:


disc_gas = Discretizer()

T( P=["Force 1"], C=[cp.gas == 0], A=[display_text(You are out of ammo!")], D=[disc_gas] )


Then for them to get the same "You are yout of ammo!" message again, they must first have at least 1 gas at some point.  After that, the next time
their gas hits 0 again, they will get the "You are yout of ammo!" message.

Easy as that :D


Note that If there are a set of 'states' that a player can have which are all mutually exclusive (i.e. the player can only be in one of these at a time),
then use the same discretizer for each.

If there are more than one set of 'states' a player can be in, then use a different discretizer for each set.


(Note however, that each discretizer takes up a deathcounter slot.  Thus try to keep declaration of them at a minimum as there are only like 1200 of these.)
























    